package com.hqyj.javaSpringBoot.modules.account.Service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hqyj.javaSpringBoot.modules.account.Service.UserService;
import com.hqyj.javaSpringBoot.modules.account.dao.UserDao;
import com.hqyj.javaSpringBoot.modules.account.dao.UserRoleDao;
import com.hqyj.javaSpringBoot.modules.account.entity.User;
import com.hqyj.javaSpringBoot.modules.account.entity.UserRole;
import com.hqyj.javaSpringBoot.modules.common.entity.Result;
import com.hqyj.javaSpringBoot.modules.common.entity.SearchBean;
import com.hqyj.javaSpringBoot.util.RedisUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @Description: User Service Impl
 * @author: HymanHu
 * @date: 2021年2月21日
 */
@Service
public class UserServiceImpl implements UserService {
	
	@Autowired
	private UserDao userDao;
	@Autowired
	private UserRoleDao userRoleDao;
	@Autowired
	private RedisUtils redisUtils;

	@Override
	public User getUserByUserNameAndPassword(String userName, String password) {
		return userDao.getUserByUserNameAndPassword(userName, password);
	}

	@Override
	public User getUserByUserName(String userName) {
		List<User> users = Optional
				.ofNullable(userDao.getUserByUserName(userName))
				.orElse(Collections.emptyList());
		return users.isEmpty() ? null : users.get(0);
	}

	@Override
	public Result<User> login(User user) {
		int loginFailMaxCount=5;
		//从数据库获取错误登录次数
		String key=String.format("failed_login_count_%s",user.getUserName());
		int loginFailCount=redisUtils.get(key)==null?0:(Integer)redisUtils.get(key);
		//如果错误登录次数>max，直接返回错误信息
		if (loginFailCount>=loginFailMaxCount){
			return new Result<User>(Result.ResultCode.failed.code,
					String.format("该账户连续登录错误%s次,账户锁定30秒"));
		}

		//获取subject
		Subject subject = SecurityUtils.getSubject();
		//包装令牌
		UsernamePasswordToken token = new UsernamePasswordToken(
			user.getUserName(), user.getPassword());
		token.setRememberMe(user.getRememberMe());

		try {
			//调用subject login方法。进行身份验证
			subject.login(token);
			//调用subject check roles方法，进行资源授权
			subject.checkRoles();
			//处理session
			subject.getSession().setAttribute("user",subject.getPrincipal());

			//登录成功，将错误次数归0
			redisUtils.set(key,0);
		}catch (Exception e){
			//redis里错误的登录次数+1
			loginFailCount+=1;
			redisUtils.set(key,loginFailCount);
			//如果错误登录次数==max，redis设置该key的过期时间
			if (loginFailCount==loginFailMaxCount){
				return new Result<User>(Result.ResultCode.failed.code,
						String.format("登录错误，还剩%s次"));//,(loginFailMaxCount-loginFailCount)


			}else {
				//返回错误消息
				redisUtils.expire(key,30);
				return new Result<User>(Result.ResultCode.failed.code,String.format("该账户连续登录错误%s次,账户锁定30秒"));


			}

		}
		return new Result<User>(Result.ResultCode.success.code, "Success", (User) subject.getPrincipal());


		/*User temp = userDao.getUserByUserNameAndPassword(user.getUserName(),
				user.getPassword());
		if (temp != null) {
			return new Result<User>(Result.ResultCode.success.code, "Success", temp);
		} else {
			return new Result<User>(Result.ResultCode.failed.code, "Failed");
		}*/

	}

	@Override
	public void logout() {
		Subject subject = SecurityUtils.getSubject();
		subject.logout();
	}

	@Override
	@Transactional
	public Result<User> insertUser(User user) {
		List<User> users = Optional
				.ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
				.orElse(Collections.emptyList());
		if (users.size() > 0) {
			return new Result<User>(Result.ResultCode.failed.code, "User Name or email is repeat.");
		}

		user.setCreatDate(LocalDateTime.now());
		user.setPassword(user.getPassword());
		userDao.insertUser(user);
		if (user.getRoles() != null) {
			user.getRoles().stream()
				.forEach(item -> {userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));});
		}
		return new Result<User>(Result.ResultCode.success.code, "Insert success", user);
	}

	@Override
	@Transactional
	public Result<User> updateUser(User user) {
		List<User> users = Optional
				.ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
				.orElse(Collections.emptyList());
		if (users.stream().filter(item -> item.getId() != user.getId()).count() > 0) {
			return new Result<User>(Result.ResultCode.failed.code, "User Name or email is repeat.");
		}
		
		userDao.updateUser(user);
		if (user.getRoles() != null && !user.getRoles().isEmpty()) {
			userRoleDao.deleteUserRoleByUserId(user.getId());
			user.getRoles().stream()
				.forEach(item -> {userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));});
		}
		
		return new Result<User>(Result.ResultCode.success.code, "Update success", user);
	}

	@Override
	public User getUserById(int id) {
		return userDao.getUserById(id);
	}

	@Override
	@Transactional
	public Result<Object> deleteUserById(int id) {
		userDao.deleteUserById(id);
		userRoleDao.deleteUserRoleByUserId(id);
		return new Result<Object>(Result.ResultCode.success.code, "Delete success");
	}

	@Override
	public PageInfo<User> getUsersBySearchBean(SearchBean searchBean) {
		searchBean.initSearchBean();
		PageHelper.startPage(searchBean.getCurrentPage(), searchBean.getPageSize());
		return new PageInfo<User>(Optional
				.ofNullable(userDao.getUsersBySearchVo(searchBean))
				.orElse(Collections.emptyList()));
	}

	@Override
	public List<User> getUsersByKeyWord(String keyWord) {
		SearchBean searchBean = new SearchBean();
		searchBean.setKeyWord(keyWord);
		searchBean.initSearchBean();
		return Optional.ofNullable(userDao.getUsersBySearchVo(searchBean)).orElse(Collections.emptyList());
	}
}
